﻿using System;
#if !SILVERLIGHT
using System.Reflection;
using System.Xml.Schema;
#endif
using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MugenInjection;
using MugenInjection.Exceptions;
using MugenInjection.Interface;
using MugenInjection.Parameters;
using MugenInjection.Xml;
using MugenInjection.Xml.Interface.Components;
using System.Linq;

namespace MugenInjectionTest.Xml
{
    [TestClass]
    public class XmlModuleTest : TestBase
    {
        [TestMethod]
        public void InvalidXmlLoadTest()
        {
            const string moduleName = "test";
            using (MugenInjector injector = GetInjector())
            {
#if SILVERLIGHT
                TestUtils.Catch<ArgumentException>(
                    () => XmlInjectorExtensions.LoadXmlModule(injector, XmlResources.InvalidXml));
#else
#if NETFX_CORE
                TestUtils.Catch<ArgumentException>(
                    () => XmlInjectorExtensions.LoadXmlModule(injector, XmlResources.InvalidXml));
#else

                TestUtils.Catch<XmlSchemaException>(
                    () => XmlInjectorExtensions.LoadXmlModule(injector, XmlResources.InvalidXml));
#endif
#endif
                TestUtils.Catch<ArgumentException>(
                    () => XmlInjectorExtensions.LoadXmlModule(injector, XmlResources.SingletonSimpleInterfaceTypeBinding));

                XmlInjectorExtensions.LoadXmlModule(injector, XmlResources.SingletonSimpleInterfaceTypeBinding, moduleName);
                Assert.IsTrue(injector.Components.Get<IXmlBindingLoaderComponent>().Modules.Contains(moduleName));
                TestUtils.Catch<ArgumentException>(() => XmlInjectorExtensions.LoadXmlModule(injector, XmlResources.SingletonSimpleInterfaceTypeBinding, moduleName));

                TestUtils.Catch<ArgumentException>(() => XmlInjectorExtensions.LoadXmlModule(injector, XmlResources.SimpleInterfaceInvalidMethodBinding, moduleName));
            }
        }

        [TestMethod]
        public void SimpleXmlLoadTest()
        {
            const string moduleName = "test";
            //Type
            using (MugenInjector injector = GetInjector())
            {
                XmlInjectorExtensions.LoadXmlModule(injector, XmlResources.SingletonSimpleInterfaceTypeBinding, moduleName);
                Assert.AreEqual(injector.Bindings.Count, 1);
                var simpleInterface = injector.Get<ISimpleInterface>();
                Assert.IsInstanceOfType(simpleInterface, typeof(SimpleClass));
                var simpleInterface1 = injector.Get<ISimpleInterface>();
                Assert.AreEqual(simpleInterface, simpleInterface1);
            }
            //Method
            using (MugenInjector injector = GetInjector())
            {
                XmlInjectorExtensions.LoadXmlModule(injector, XmlResources.SimpleInterfaceValidMethodBinding, moduleName);
                Assert.AreEqual(injector.Bindings.Count, 1);
                var simpleInterface = injector.Get<ISimpleInterface>();
                Assert.IsInstanceOfType(simpleInterface, typeof(SimpleClass));
                var simpleInterface1 = injector.Get<ISimpleInterface>();
                Assert.AreEqual(simpleInterface, simpleInterface1);
            }
            //Const
            using (MugenInjector injector = GetInjector())
            {
                XmlInjectorExtensions.LoadXmlModule(injector, XmlResources.StringConstBinding, moduleName);
                Assert.AreEqual(injector.Bindings.Count, 1);
                Assert.AreEqual(injector.Get<string>(), "test");
            }
        }

        [TestMethod]
        public void SimpleXmlWhenIntoStringTest()
        {
            const string moduleName = "test";
            //Type
            using (MugenInjector injector = GetInjector())
            {
                XmlInjectorExtensions.LoadXmlModule(injector, XmlResources.SimpleInterfaceWhenString, moduleName);
                Assert.AreEqual(injector.Bindings.Count, 1);
                TestUtils.Catch<BindingNotFoundException>(() => injector.Get<ISimpleInterface>());
                var simpleInterface = injector.GetInto<ISimpleInterface>(typeof(string).GetTypeInfo());
                Assert.IsInstanceOfType(simpleInterface, typeof(SimpleClass));
                var simpleInterface1 = injector.GetInto<ISimpleInterface>(typeof(string).GetTypeInfo());
                Assert.AreEqual(simpleInterface, simpleInterface1);
            }
        }


        [TestMethod]
        public void SimpleXmlNamedTest()
        {
            const string moduleName = "test";
            //Type
            using (MugenInjector injector = GetInjector())
            {
                XmlInjectorExtensions.LoadXmlModule(injector, XmlResources.SimpleNamed, moduleName);
                Assert.AreEqual(injector.Bindings.Count, 1);
                TestUtils.Catch<BindingNotFoundException>(() => injector.Get<ISimpleInterface>());
                var simpleInterface = injector.Get<ISimpleInterface>(moduleName);
                Assert.IsInstanceOfType(simpleInterface, typeof(SimpleClass));
                var simpleInterface1 = injector.Get<ISimpleInterface>(moduleName);
                Assert.AreEqual(simpleInterface, simpleInterface1);
            }
        }

        [TestMethod]
        public void SimpleParametersTest()
        {
            const string moduleName = "test";
            //Type
            using (MugenInjector injector = GetInjector())
            {
                XmlInjectorExtensions.LoadXmlModule(injector, XmlResources.SimpleParameters, moduleName);
                Assert.AreEqual(injector.Bindings.Count, 1);
                var binding = injector.Bindings.First();
                Assert.AreEqual(binding.Parameters.Count, 3);
                var constructor = binding.Parameters.First(parameter => parameter is ConstructorParameter);
                var property = binding.Parameters.First(parameter => parameter is PropertyParameter);
                var method = binding.Parameters.First(parameter => parameter is MethodParameter) as MethodParameter;

                Assert.AreEqual(constructor.Name, "Constructor");
                Assert.AreEqual(constructor.GetValue(null), "Constructor");

                Assert.AreEqual(property.Name, "Property");
                Assert.AreEqual(property.GetValue(null), "Property");

                Assert.AreEqual(method.Name, "Method");
                Assert.AreEqual(method.MethodName, "Method");
                Assert.AreEqual(method.GetValue(null), "Method");

                Assert.AreEqual(binding.Settings["key"], "value");
            }
        }

        #region Static methods

        public static ISimpleInterface FactoryMethodInvalid()
        {
            return new SimpleClass();
        }

        public static ISimpleInterface FactoryMethod(IBindingContext bindingContext)
        {
            return new SimpleClass();
        }

        #endregion
    }

    #region Xml binding types

    public interface ISimpleInterface
    {
    }

    public class SimpleClass : ISimpleInterface
    {
    }

    #endregion
   
}